package cz.muni.fi.pv112.cranesimulator.models.scene;

import com.jogamp.opengl.util.texture.Texture;
import com.jogamp.opengl.util.texture.TextureIO;
import cz.muni.fi.pv112.cranesimulator.models.Model;
import cz.muni.fi.pv112.cranesimulator.models.crane.Liftable;
import cz.muni.fi.pv112.cranesimulator.models.crane.LiftingZone;
import cz.muni.fi.pv112.cranesimulator.models.crane.parts.Magnet;
import cz.muni.fi.pv112.cranesimulator.scene.Scene;
import java.io.IOException;
import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import static cz.muni.fi.pv112.cranesimulator.utils.Calculator.recalculateCoordinatesToSceneCoordinateSystem;
import static cz.muni.fi.pv112.cranesimulator.utils.handlers.opengl.DisplayListHandler.storeModelToDisplayList;
import static cz.muni.fi.pv112.cranesimulator.utils.handlers.opengl.TextureHandler.loadTextures;

/**
 *
 * @author Michal Ďuriš
 */
public class Container extends Model implements Liftable {

    private static final float height = 30.0f;
    private static final float halfWidth = 10.0f;
    private static final float halfDeep = 20.0f;

    private static final LiftingZone[] liftingZones = {new LiftingZone(
        new float[] {halfWidth, height, halfDeep}, Magnet.MAGNET_RADIUS),
                                                       new LiftingZone(
                                                       new float[] {-halfWidth,
                                                                    height,
                                                                    halfDeep},
                                                       Magnet.MAGNET_RADIUS),
                                                       new LiftingZone(
                                                       new float[] {-halfWidth,
                                                                    height,
                                                                    -halfDeep},
                                                       Magnet.MAGNET_RADIUS),
                                                       new LiftingZone(
                                                       new float[] {halfWidth,
                                                                    height,
                                                                    -halfDeep},
                                                       Magnet.MAGNET_RADIUS),
                                                       new LiftingZone(
                                                       new float[] {0.0f, height,
                                                                    0.0f},
                                                       Magnet.MAGNET_RADIUS),};

    private final Texture[] textures = new Texture[6];

    private static final String[] texturePath = {
        "/cz/muni/fi/pv112/cranesimulator/resources/textures/models/container/ContainerDoors.png",
        "/cz/muni/fi/pv112/cranesimulator/resources/textures/models/container/Container.png"};

    private static final float[][] vertexCoords = { /*
         * Front side
         */
        {-halfWidth, height, halfDeep},
        {halfWidth, height, halfDeep},
        {halfWidth, 0.0f, halfDeep},
        {-halfWidth, 0.0f, halfDeep},
        /*
         * Back side
         */
        {halfWidth, 0.0f, -halfDeep},
        {-halfWidth, 0.0f, -halfDeep},
        {-halfWidth, height, -halfDeep},
        {halfWidth, height, -halfDeep},
        /*
         * Right side
         */
        {halfWidth, height, halfDeep},
        {halfWidth, height, -halfDeep},
        {halfWidth, 0.0f, -halfDeep},
        {halfWidth, 0.0f, halfDeep},
        /*
         * Left side
         */
        {-halfWidth, height, halfDeep},
        {-halfWidth, height, -halfDeep},
        {-halfWidth, 0.0f, -halfDeep},
        {-halfWidth, 0.0f, halfDeep},
        /*
         * Top side
         */
        {halfWidth, height, halfDeep},
        {halfWidth, height, -halfDeep},
        {-halfWidth, height, -halfDeep},
        {-halfWidth, height, halfDeep},
        /*
         * Bottom side
         */
        {halfWidth, 0.0f, halfDeep},
        {-halfWidth, 0.0f, halfDeep},
        {-halfWidth, 0.0f, -halfDeep},
        {halfWidth, 0.0f, -halfDeep}
    };

    private static final float[][] textureCoords = {
        /*
         * Front side
         */
        {0, 1.004f},
        {1, 1.004f},
        {1, 0},
        {0, 0},
        /*
         * Back side
         */
        {0.5f, 0},
        {0, 0},
        {0, 1},
        {0.5f, 1},
        /*
         * Right side
         */
        {0, 1},
        {1, 1},
        {1, 0},
        {0, 0},
        /*
         * Left side
         */
        {0, 1},
        {1, 1},
        {1, 0},
        {0, 0},
        /*
         * Top side
         */
        {0, 0},
        {1, 0},
        {1, 1},
        {0, 1},
        /*
         * Bottom side
         */
        {0, 0},
        {0, 1},
        {1, 1},
        {1, 0}
    };

    private static final float[][] normalCoords = {
        /*
         * Front side
         */
        {0, 0, 1},
        {0, 0, 1},
        {0, 0, 1},
        {0, 0, 1},
        /*
         * Back side
         */
        {0, 0, -1},
        {0, 0, -1},
        {0, 0, -1},
        {0, 0, -1},
        /*
         * Right side
         */
        {1, 0, 0},
        {1, 0, 0},
        {1, 0, 0},
        {1, 0, 0},
        /*
         * Left side
         */
        {-1, 0, 0},
        {-1, 0, 0},
        {-1, 0, 0},
        {-1, 0, 0},
        /*
         * Top side
         */
        {0, 1, 0},
        {0, 1, 0},
        {0, 1, 0},
        {0, 1, 0},
        /*
         * Bottom side
         */
        {0, -1, 0},
        {0, -1, 0},
        {0, -1, 0},
        {0, -1, 0}
    };

    public Container() {
    }

    public void init(GL gl) {
        try {
            Texture[] loadedTextures = loadTextures(gl, texturePath, true,
                    TextureIO.PNG);

            textures[0] = loadedTextures[0];

            for (int i = 1; i < 6; i++) {
                textures[i] = loadedTextures[1];
            }

            displayListID = storeModelToDisplayList(gl.getGL2(), this, textures,
                    GL2.GL_CLAMP_TO_EDGE,
                    GL2.GL_CLAMP_TO_EDGE);

            updateLiftingZonesPositions();

        } catch (IOException ex) {
            //@TODO: maybe throw some runtime error or something
            System.err.println("Error during loading textures !!!");
        }
    }

    @Override
    public float[][] getVertexCoords() {
        return vertexCoords;
    }

    @Override
    public float[][] getTextureCoords() {
        return textureCoords;
    }

    @Override
    public float[][] getNormalCoords() {
        return normalCoords;
    }

    @Override
    public float getHeight() {
        return height;
    }

    @Override
    public LiftingZone[] getLiftingZones() {
        updateLiftingZonesPositions();
        return liftingZones;
    }

    private void updateLiftingZonesPositions() {
        for (LiftingZone liftingZone : liftingZones) {
            liftingZone.setCurrentPosition(
                    recalculateCoordinatesToSceneCoordinateSystem(liftingZone
                            .getStartPosition()[Scene.X_AXIS]
                            + displacement[Scene.X_AXIS],
                            liftingZone
                            .getStartPosition()[Scene.Y_AXIS]
                            + displacement[Scene.Y_AXIS],
                            liftingZone
                            .getStartPosition()[Scene.Z_AXIS]
                            + displacement[Scene.Z_AXIS],
                            rotation));
        }
    }

}
